<?php
/**
 * 框架主程序类
 * @copyright Copyright(c) 2020 WillPHP
 * @author DaSongzi <24203741@qq.com/113344.com>
 * @version 2.0
 * @since 2020-09-17
 */
namespace wiphp;
final class App {
	private static $_map = ['wiphp'=>PATH_CORE, 'home'=>APP_PATH, 'extend'=>PATH_EXTEND]; //自动加载路径配置
	private static $_config = []; //应用配置
	private static $_request = []; //$_GET或$_POST请求参数
	//启动框架
	public static function start() {
		spl_autoload_register('\wiphp\App::autoload'); //注册自动加载
		set_error_handler('\wiphp\App::wiError'); //设置错误处理
		set_exception_handler('\wiphp\App::wiException'); //设置异常处理
		if(!is_dir(APP_PATH.'/controller') || !is_dir(PATH_RUNTIME)){
			Build::app(); //生成应用
		}
		self::_load_config(); //加载配置
		self::_parse_request(); //处理请求参数
		self::_dispatch(); //请求分发
		if (APP_DEBUG) Debug::show(); //显示调试信息
	}
	//处理请求参数
	private static function _parse_request() {
		$analysis = Route::parseUrl();
		$params = $analysis['param'];		
		array_walk_recursive($params, 'self::_parse_param');
		self::$_request = $params;		
		$route = explode('/', trim($analysis['route'],'/'));
		define('__MODULE__', ucfirst($route[0]));
		define('__ACTION__', $route[1]);		
	}
	//处理参数过滤
	private static function _parse_param(&$value, $key) {
		$filters = C('param_filter');
		if (!is_numeric($key) && in_array($key, array_keys($filters))) {
			$fn = $filters[$key];
			if (function_exists($fn)) {
				$value = $fn($value);
			}
		}
		if (!get_magic_quotes_gpc() && !is_array($value)) {
			$value = addslashes(trim($value));
		}
	}	
	//请求分发
	private static function _dispatch() {
		$classname = ucfirst(__MODULE__);
		$class = strtr('home/controller/'.$classname.'Controller', '/', '\\');
		$method = __ACTION__;
		if (!method_exists($class, $method)) {
			$class = 'home\controller\EmptyController';
			$method = '_empty';
		}
		if (!method_exists($class, $method)) self::halt(__MODULE__.'Controller->'.$method.'() does not exist.');
		$action = new \ReflectionMethod($class, $method);
		$args = [];
		foreach ($action->getParameters() as $arg) {
			$name = $arg->getName();
			$default = $arg->isOptional()? $arg->getDefaultValue() : '';
			$args[] = isset(self::$_request[$name])? self::$_request[$name] : $default;
		}
		$res = (new $class)->$method(...$args);
		if (is_scalar($res)) {
			echo $res;
		} elseif (is_null($res)) {
			return;
		} else {
			echo json($res);
		}
	}
	//获取请求参数
	public static function getRequest($name = '', $default = '', $fns = '') {
		$req = self::$_request['req'];
		$data = $default;
		if (empty($name)) {
			$data = $req;
		} elseif (isset($req[$name])) {
			$data = $req[$name];
		}
		if ($fns && !empty($data)) {
			$fns = explode(',', $fns);
			foreach ($fns as $fn) {
				if(function_exists($fn)) {
					$data = is_array($data) ? array_map($fn, $data) : $fn($data);
				}
			}
		}
		return $data;
	}
	//加载应用配置
	private static function _load_config() {
		$configs = ['app', 'database', 'site'];
		foreach ($configs as $conf) {
			self::$_config = array_merge(self::$_config, self::loadConfig($conf));
		}		
	}
	//从配置文件中获取相关配置
	public static function loadConfig($fname) {
		$cfiles = [WPHP_URI.'/config/'.$fname.'.php', APP_PATH.'/config/'.$fname.'.php'];
		$configs = [];
		foreach ($cfiles as $file) {
			if (file_exists($file)) {
				$config = require $file;
				$configs = array_merge($configs, $config);
			}
		}
		return $configs;
	}
	//获取或设置应用配置
	public static function getConfig($name = '', $val = '') {
		if ($name == '') {
			return self::$_config;
		} elseif ('' === $val) {
			return isset(self::$_config[$name])? self::$_config[$name] : '';
		} elseif (is_null($val)) {
			unset(self::$_config[$name]);
			return null;
		} else {
			self::$_config[$name] = $val;
			return $val;
		}
	}
	//自动加载
	public static function autoload($class) {		
		$end = strpos($class, '\\');
		if (false !== $end) {
			$map = substr($class, 0, $end);
			if (isset(self::$_map[$map])) {
				$fname = substr($class, strlen($map)).'.php';
				$file = strtr(self::$_map[$map].$fname, '\\', '/');
				if (is_readable($file)) include $file;
			}
			if (APP_DEBUG) Debug::set($class, 'inc');			
		}
	}
	//错误处理
	public static function wiError($errno, $errstr, $errfile, $errline) {
		$info = '['.date('Y-m-d H:i:s').'] file: '.basename($errfile).' line: '.$errline.' Error: '.$errstr;
		if (APP_DEBUG) {
			Debug::set($info, 'info');
		} else {
			$file = PATH_LOG.'/log_'.APP_NAME.'_'.basename($errfile,'.php').'_'.$errline.'_'.date('Ymd').'.log';
			if (!file_exists($file)) file_put_contents($file, $info);
			if (($errno != E_NOTICE) && ($errno < 2048)) self::halt('Website error,Please contact webmaster.');
		}
	}
	//异常处理
	public static function wiException($e) {
		$errstr = $e->getMessage();
		$errfile = $e->getFile();
		$errline = $e->getLine();
		$info = '['.date('Y-m-d H:i:s').'] file: '.basename($errfile).' line: '.$errline.' Error: '.$errstr;
		if (APP_DEBUG) {
			Debug::set($info, 'info');
			Debug::show();			
		} else {
			$file = PATH_LOG.'/log_'.APP_NAME.'_'.basename($errfile,'.php').'_'.$errline.'_'.date('Ymd').'.log';
			if (!file_exists($file)) file_put_contents($file, $info);
			self::halt($errstr);
		}
	}
	//抛出错误
	public static function halt($info) {
		$shtml = file_get_contents(WPHP_PATH.'/wihtml/halt.html');
		$shtml = str_replace('__INFO__', $info, $shtml);
		exit($shtml);
	}
	//获取运行时间
	public static function getRuntime() {
		return round((microtime(true) - START_TIME) , 4);
	}
}